home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / dte5_1.zip / WINDOW.C < prev    next >
C/C++ Source or Header  |  1991-02-06  |  20KB  |  663 lines

  1. /*
  2.  * Written by Douglas Thomson (1989/1990)
  3.  *
  4.  * This source code is released into the public domain.
  5.  */
  6.  
  7. /*
  8.  * Name:    dte - Doug's Text Editor program - window module
  9.  * Purpose: This file contains the code associated with opening and sizing
  10.  *           windows, and also displaying the help window.
  11.  * File:    window.c
  12.  * Author:  Douglas Thomson
  13.  * System:  this file is intended to be system-independent
  14.  * Date:    October 12, 1989
  15.  */
  16.  
  17. #ifdef HPXL
  18. #include "commonh"
  19. #include "utilsh"
  20. #include "windowh"
  21. #else
  22. #include "common.h"
  23. #include "utils.h"
  24. #include "window.h"
  25. #endif
  26.  
  27. /*
  28.  * prototypes for all functions in this file
  29.  */
  30. int open_window ARGS((windows *window, char *name));
  31. void new_window ARGS((char *auto_name, windows *window));
  32. void choose_window ARGS((char *name, windows *window));
  33. void size_window ARGS((windows *window));
  34. void get_help ARGS((windows *window));
  35. void finish ARGS((windows *window));
  36. int create_window ARGS((windows *prev, int top, int bottom, text_ptr cursor,
  37.         file_infos *file));
  38. int create_file ARGS((file_infos *prev));
  39.  
  40. /*
  41.  * Name:    open_window
  42.  * Purpose: To open a new window, and load a file into it.
  43.  * Date:    October 10, 1989
  44.  * Passed:  window:   information allowing access to the current window
  45.  *          name:     name of file to read
  46.  * Returns: OK if window opened successfully
  47.  *          ERROR if anything went wrong
  48.  * Notes:   If window is NULL, then this is the first window, and should
  49.  *           take up the entire screen.
  50.  *          If window is not NULL, then the new window should start on the
  51.  *           line below the cursor line of the current window, and continue
  52.  *           down to what used to be the bottom of the current window. If
  53.  *           this does not make enough room for the new window, then an
  54.  *           error is reported, and no new window is created.
  55.  */
  56. int open_window(window, name)
  57. windows *window;
  58. char *name;
  59. {
  60.     int existing;       /* did the file already exist? */
  61.     file_infos *file;   /* file structure for file belonging to new window */
  62.     int ccol;           /* cursor column in new window */
  63.     text_ptr cursor;    /* start of cursor line in new window */
  64.     windows *wp;        /* used for scanning windows for same file name */
  65.     int file_attrib;    /* rwx bits for new file */
  66.  
  67.     if (window) {
  68.         /*
  69.          * check that there is room for the window (no need if this is the
  70.          *  first window)
  71.          */
  72.         if (window->bottom_line - window->cline < 2 ||
  73.                 g_display.nlines-3 - window->cline < 2) {
  74.             error(WARNING, "move cursor up first");
  75.             return ERROR;
  76.         }
  77.     }
  78.  
  79.     /*
  80.      * look for a window whose file has the same name. Check the
  81.      *  current window (if any) first.
  82.      * If there is already a window open on the same file, then the
  83.      *  new window can share the existing file structure, and the new
  84.      *  window's cursor should be placed in the same spot in the file.
  85.      */
  86.     if (window && strcmp(name, window->file_info->file_name) == 0) {
  87.         file = window->file_info;
  88.         existing = TRUE;
  89.         cursor = window->cursor;
  90.         ccol = window->ccol;
  91.  
  92.         /*
  93.          * One line is taken by the status line, and the cursor line
  94.          *  is duplicated. All the other lines can be kept.
  95.          */
  96.         window_scroll_down(window->cline+1, window->bottom_line);
  97.         window_scroll_down(window->cline+2, window->bottom_line);
  98.     }
  99.     else {
  100.         /*
  101.          * Not same file as current window, so try other windows
  102.          */
  103.         file = NULL;
  104.         for (wp=g_status.window_list; wp; wp = wp->next) {
  105.             if (strcmp(name, wp->file_info->file_name) == 0) {
  106.                 file = wp->file_info;
  107.                 break;
  108.             }
  109.         }
  110.         if (file) {
  111.             /*
  112.              * file was already open somewhere
  113.              */
  114.             existing = TRUE;
  115.             cursor = wp->cursor;
  116.             ccol = wp->ccol;
  117.         }
  118.         else {
  119.             /*
  120.              * file was not open, so see if it exists on disk
  121.              */
  122.             file_attrib = hw_fattrib(name);
  123.             existing = file_attrib != ERROR;
  124.             if (existing) {
  125.                 if (load_file(name, FALSE) != OK) {
  126.                     /*
  127.                      * The file existed, but was not a plain text file
  128.                      *  or we ran out of memory. In any case, give up
  129.                      *  on the new window.
  130.                      */
  131.                     return ERROR;
  132.                 }
  133.             }
  134.             else {
  135.                 /*
  136.                  * make sure this gets set properly even if there is no file!
  137.                  */
  138.                 g_status.temp_end = g_status.end_mem;
  139.             }
  140.  
  141.             /*
  142.              * allocate a file structure for the new file
  143.              */
  144.             if (create_file(window ? window->file_info : NULL) == ERROR) {
  145.                 error(WARNING, "out of memory");
  146.                 return ERROR;
  147.             }
  148.             file = window ? window->file_info->next : g_status.file_list;
  149.  
  150.             /*
  151.              * set up all the info we need to know about a file, and
  152.              *  record that we have used some more memory.
  153.              */
  154.             strcpy(file->file_name, name);
  155.             file->file_attrib = file_attrib;
  156.             cursor = g_status.end_mem;
  157.             ccol = 0;
  158.             file->start_text = g_status.end_mem;
  159.             *g_status.temp_end = '\0';
  160.             g_status.end_mem = g_status.temp_end + 1;
  161.             file->end_text = g_status.end_mem;
  162.  
  163.             /*
  164.              * file has not been modified yet
  165.              */
  166.             g_status.unsaved = FALSE;
  167.         }
  168.     }
  169.  
  170.     /*
  171.      * Now that we have the file, allocate a window to view the file
  172.      */
  173.     if (create_window(window, window ? window->cline+1 : 0,
  174.             window ? window->bottom_line : g_display.nlines-1, cursor,
  175.             file) == ERROR) {
  176.         error(WARNING, "out of memory");
  177.  
  178.         /*
  179.          * This is a real nuisance. We had room for the file and the
  180.          *  file structure, but not enough for the window as well.
  181.          * Now we must free all the memory that has already been
  182.          *  allocated.
  183.          */
  184.         if (file->ref_count == 0) {
  185.             if (file->prev) {
  186.                 file->prev->next = file->next;
  187.             }
  188.             else {
  189.                 g_status.file_list = file->next;
  190.             }
  191.             if (file->next) {
  192.                 file->next->prev = file->prev;
  193.             }
  194.             g_status.end_mem = file->start_text;
  195.             free(file);
  196.         }
  197.         return ERROR;
  198.     }
  199.  
  200.     if (window) {
  201.         /*
  202.          * record that the current window has lost some lines from
  203.          *  the bottom for the new window, and adjust its page size
  204.          *  etc accordingly.
  205.          */
  206.         window->bottom_line = window->cline;
  207.         setup_window(window);
  208.  
  209.         /*
  210.          * we have now finished with the old window, and can concentrate
  211.          *  on the new one.
  212.          */
  213.         window = window->next;
  214.     }
  215.     else {
  216.         window = g_status.window_list;
  217.     }
  218.  
  219.     /*
  220.      * tell the user if a new file has been created, in case this was not
  221.      *  intentional.
  222.      * Eventually, the user should be given a chance to change the name
  223.      *  of the file and try again.
  224.      */
  225.     if (!existing) {
  226.         error(DIAG, "'%s' is a new file", name);
  227.         file->new_file = TRUE;
  228.     }
  229.  
  230.     /*
  231.      * set up the new cursor position as appropriate
  232.      */
  233.     window->cursor = cursor;
  234.     window->ccol = ccol;
  235.  
  236.     /*
  237.      * the new window becomes the current window.
  238.      */
  239.     g_status.current_window = window;
  240.     return OK;
  241. }
  242.  
  243. /*
  244.  * Name:    new_window
  245.  * Purpose: To open a new window, and ask the user which file to load into it.
  246.  * Date:    October 10, 1989
  247.  * Passed:  auto_name: name of file (NULL if we should prompt the user)
  248.  *          window:    information allowing access to the current window
  249.  */
  250. void new_window(auto_name, window)
  251. char *auto_name;
  252. windows *window;
  253. {
  254.     char name[MAX_COLS];
  255.  
  256.     /*
  257.      * check that there is room for the window
  258.      */
  259.     if (window->bottom_line - window->cline < 2 ||
  260.             g_display.nlines-3 - window->cline < 2) {
  261.         error(WARNING, "move cursor up first");
  262.         return;
  263.     }
  264.  
  265.     /*
  266.      * get the name of the file
  267.      */
  268.     if (auto_name) {
  269.         strcpy(name, auto_name);
  270.     }
  271.     else {
  272.         strcpy(name, window->file_info->file_name);
  273.         if (get_name("File to edit: ", 1, name) == ERROR) {
  274.             return;
  275.         }
  276.     }
  277.  
  278.     open_window(window, name);
  279. }
  280.  
  281. /*
  282.  * Name:    choose_window
  283.  * Purpose: To select either an existing window or a new one.
  284.  * Date:    October 10, 1989
  285.  * Passed:  name:     name of file (NULL normally)
  286.  *          window:   information allowing access to the current window
  287.  * Notes:   If "name" is not NULL, then the named file will be opened
  288.  *           in a new window.
  289.  *          If the user enters the word "new" (the default), then a new
  290.  *           window will be created.
  291.  *          If the user enters a number, then the relevant window will
  292.  *           become the new current window.
  293.  *          Windows are numbered starting with the current window as 0.
  294.  *           Windows above have negative numbers, and windows below have
  295.  *           positive numbers.
  296.  */
  297. void choose_window(name, window)
  298. char *name;
  299. windows *window;
  300. {
  301.     char number[MAX_COLS];  /* window selected by user */
  302.     int count;              /* existing window number */
  303.  
  304.     un_copy_line(window);
  305.  
  306.     /*
  307.      * if the file in this window has been modified, then ask the user
  308.      *  if it should be saved. This may be important, since the recovery
  309.      *  file will contain the file for the new window, meaning that there
  310.      *  would be no way to recover changes made in the old window.
  311.      */
  312.     if (window->file_info->modified) {
  313.         sprintf(number, "Save '%s' first? (y/n): ",
  314.                 window->file_info->file_name);
  315.         set_prompt(number, 1);
  316.         switch (display(get_yn, 1)) {
  317.         case A_YES:
  318.             save_file(window, SAVE_NORMAL);
  319.             break;
  320.         case A_NO:
  321.             g_status.unsaved = FALSE;
  322.             if (g_status.recovery[0]) {
  323.                 hw_unlink(g_status.recovery);
  324.                 g_status.recovery[0] = '\0';
  325.             }
  326.             break;
  327.         default:
  328.             return;
  329.         }
  330.     }
  331.  
  332.     /*
  333.      * If the name was already specified, then go ahead and open it. This
  334.      *  is used for help windows.
  335.      */
  336.     if (name) {
  337.         new_window(name, window);
  338.         return;
  339.     }
  340.  
  341.     /*
  342.      * get the desired destination. The default is to create a new
  343.      *  window
  344.      */
  345.     strcpy(number, "new");
  346.     if (get_name("Window number or new: ", 1, number) == ERROR) {
  347.         return;
  348.     }
  349.  
  350.     if (strcmp(number, "new") == 0) {
  351.         /*
  352.          * user wanted to create a new window
  353.          */
  354.         new_window(NULL, window);
  355.     }
  356.     else {
  357.         /*
  358.          * user wanted to switch to an existing window
  359.          */
  360.         if (strcmp(number, "+") == 0) {
  361.             count = 1;
  362.         }
  363.         else if (strcmp(number, "-") == 0) {
  364.             count = -1;
  365.         }
  366.         else {
  367.             count = atoi(number);
  368.         }
  369.  
  370.         /*
  371.          * follow pointers until required window is located (or we run
  372.          *  out of windows)
  373.          */
  374.         if (count < 0) {
  375.             while (count++ < 0 && window) {
  376.                 window = window->prev;
  377.             }
  378.         }
  379.         else {
  380.             while (count-- > 0 && window) {
  381.                 window = window->next;
  382.             }
  383.         }
  384.  
  385.         /*
  386.          * record a new current window, or report an error if the window
  387.          *  did not exist
  388.          */
  389.         if (window) {
  390.             g_status.current_window = window;
  391.         }
  392.         else {
  393.             error(WARNING, "no such window");
  394.         }
  395.     }
  396. }
  397.  
  398. /*
  399.  * Name:    size_window
  400.  * Purpose: To change the size of the current and one other window.
  401.  * Date:    October 10, 1989
  402.  * Passed:  window:   information allowing access to the current window
  403.  * Notes:   The cursor line will become the bottom line of the window,
  404.  *           and the window below will grow. (If the current window is
  405.  *           the bottom window, the cursor line will become the top line,
  406.  *           and the window above will grow.)
  407.  */
  408. void size_window(window)
  409. windows *window;
  410. {
  411.     /*
  412.      * try to give more lines to the window below
  413.      */
  414.     if (window->next) {
  415.         window->next->top_line = window->cline+2;
  416.         window->bottom_line = window->cline;
  417.         setup_window(window->next);
  418.     }
  419.     else {
  420.         /*
  421.          * This is the bottom window, so cursor line becomes the new
  422.          *  top of the window
  423.          */
  424.         if (window->prev) {
  425.             window->prev->bottom_line = window->cline-2;
  426.             window->top_line = window->cline;
  427.             setup_window(window->prev);
  428.         }
  429.     }
  430.     setup_window(window);
  431. }
  432.  
  433. /*
  434.  * Name:    get_help
  435.  * Purpose: To read in the help file, and display it for the user to read
  436.  *           and scroll through.
  437.  * Date:    October 1, 1989
  438.  * Passed:  window: information allowing access to the current window
  439.  * Notes:   The help file is read into a normal window (it can even be
  440.  *           edited, although most users will not be able to save the
  441.  *           edited version!)
  442.  */
  443. void get_help(window)
  444. windows *window;
  445. {
  446.     /*
  447.      * don't risk destroying current line
  448.      */
  449.     un_copy_line(window);
  450.  
  451.     /*
  452.      * If file exists, then load it
  453.      */
  454.     if (hw_fattrib(g_status.help_file) == ERROR) {
  455.         error(DIAG, "sorry, no help file available");
  456.         return;
  457.     }
  458.  
  459.     /*
  460.      * open new window for help
  461.      */
  462.     choose_window(g_status.help_file, window);
  463. }
  464.  
  465. /*
  466.  * Name:    finish
  467.  * Purpose: To remove the current window, and terminate the program if no
  468.  *           more windows are left.
  469.  * Date:    October 1, 1989
  470.  * Passed:  window: information allowing access to the current window
  471.  * Notes:   If more windows are left, then the lines from this window
  472.  *           are inherited by the window above (if any, otherwise the
  473.  *           window below).
  474.  *          If no other window referred to the same file, then the space
  475.  *           taken by the file must be freed.
  476.  */
  477. void finish(window)
  478. windows *window;
  479. {
  480.     windows *wp;        /* for scanning other windows */
  481.     file_infos *file;   /* for scanning other files */
  482.     long number;        /* number of bytes removed / copied */
  483.  
  484.     un_copy_line(window);
  485.  
  486.     /*
  487.      * remove old window from list
  488.      */
  489.     if (window->prev == NULL) {
  490.         if (window->next == NULL) {
  491.             terminate();
  492.             exit(0);
  493.         }
  494.         g_status.window_list = window->next;
  495.     }
  496.     else {
  497.         window->prev->next = window->next;
  498.     }
  499.     if (window->next) {
  500.         window->next->prev = window->prev;
  501.     }
  502.  
  503.     /*
  504.      * give lines to adjacent window (preferably above)
  505.      */
  506.     if (window->prev)  {
  507.         wp = window->prev;
  508.         wp->bottom_line = window->bottom_line;
  509.     }
  510.     else {
  511.         wp = window->next;
  512.         wp->top_line = window->top_line;
  513.     }
  514.  
  515.     /*
  516.      * fix up things like page size and center line
  517.      */
  518.     setup_window(wp);
  519.  
  520.     /*
  521.      * The window above (or possibly below) becomes the new current
  522.      *  window.
  523.      */
  524.     g_status.current_window = wp;
  525.  
  526.     /*
  527.      * free unused file memory if necessary
  528.      */
  529.     if (--window->file_info->ref_count == 0) {
  530.         /*
  531.          * no window now refers to this file, so remove file from the list
  532.          */
  533.         file = window->file_info;
  534.         if (file->prev == NULL) {
  535.             g_status.file_list = file->next;
  536.         }
  537.         else {
  538.             file->prev->next = file->next;
  539.         }
  540.         if (file->next) {
  541.             file->next->prev = file->prev;
  542.         }
  543.  
  544.         /*
  545.          * close up the gap in the memory buffer
  546.          */
  547.         number = g_status.end_mem - file->end_text;
  548.         hw_move(file->start_text, file->end_text, number);
  549.         number = file->end_text - file->start_text;
  550.         fix_marks(window, file->start_text, -number);
  551.  
  552.         /*
  553.          * free the memory taken by the file structure
  554.          */
  555.         free(window->file_info);
  556.     }
  557.  
  558.     /*
  559.      * free the memory taken by the window structure
  560.      */
  561.     free(window);
  562. }
  563.  
  564. /*
  565.  * Name:    create_window
  566.  * Purpose: To allocate space for a new window structure, and set up some
  567.  *           of the relevant fields.
  568.  * Date:    October 10, 1989
  569.  * Passed:  prev:   the previous window (or NULL)
  570.  *          top:    the top line of the new window
  571.  *          bottom: the bottom line of the new window
  572.  *          cursor: the cursor position for the new window
  573.  *          file:   the file structure to be associated with the new window
  574.  * Returns: OK if window could be created
  575.  *          ERROR if out of memory
  576.  */
  577. int create_window(prev, top, bottom, cursor, file)
  578. windows *prev;
  579. int top;
  580. int bottom;
  581. text_ptr cursor;
  582. file_infos *file;
  583. {
  584.     windows *window;  /* the new window structure */
  585.  
  586.     /*
  587.      * allocate space for new window structure
  588.      */
  589.     if ((window = (windows *)calloc(1, sizeof(windows))) == NULL) {
  590.         error(WARNING, "out of memory for window");
  591.         return ERROR;
  592.     }
  593.  
  594.     /*
  595.      * set up appropriate fields
  596.      */
  597.     window->file_info = file;
  598.     window->top_line = top+1;
  599.     window->bottom_line = bottom;
  600.     window->cline = top+1;
  601.     setup_window(window);
  602.     window->cursor = cursor;
  603.  
  604.     /*
  605.      * add window into window list
  606.      */
  607.     window->prev = prev;
  608.     if (prev) {
  609.         if (prev->next) {
  610.             prev->next->prev = window;
  611.         }
  612.         window->next = prev->next;
  613.         prev->next = window;
  614.     }
  615.     else {
  616.         g_status.window_list = window;
  617.     }
  618.  
  619.     /*
  620.      * record that another window is referencing this file
  621.      */
  622.     ++file->ref_count;
  623.     return OK;
  624. }
  625.  
  626. /*
  627.  * Name:    create_file
  628.  * Purpose: To allocate space for a new file structure, and set up some
  629.  *           of the relevant fields.
  630.  * Date:    October 10, 1989
  631.  * Passed:  prev:   the previous file (or NULL)
  632.  * Returns: OK if file structure could be created
  633.  *          ERROR if out of memory
  634.  */
  635. int create_file(prev)
  636. file_infos *prev;
  637. {
  638.     file_infos *file;
  639.  
  640.     if ((file = (file_infos *)calloc(1, sizeof(file_infos))) == NULL) {
  641.         error(WARNING, "out of memory for file info");
  642.         return ERROR;
  643.     }
  644.  
  645.     /*
  646.      * add file into list
  647.      */
  648.     file->prev = prev;
  649.     if (prev) {
  650.         if (prev->next) {
  651.             prev->next->prev = file;
  652.         }
  653.         file->next = prev->next;
  654.         prev->next = file;
  655.     }
  656.     else {
  657.         g_status.file_list = file;
  658.     }
  659.  
  660.     return OK;
  661. }
  662.  
  663.